home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / INTER53G.ZIP / INT2TPH.ZIP / TPH.PAS < prev    next >
Pascal/Delphi Source File  |  1996-07-31  |  20KB  |  803 lines

  1. { TPH unit for the Interrupt List -> .TPH compiler.            }
  2. { The software included, data formats and basic algorithms are }
  3. { copyright (C) 1996 by Slava Gostrenko. All rights reserved.  }
  4.  
  5. {$X+}
  6. unit
  7.   TPH;
  8.  
  9. interface
  10.  
  11. uses
  12.   Objects;
  13.  
  14. const
  15.   HexChars = ['0'..'9', 'A'..'F', 'a'..'f'];
  16.  
  17.   TPFileStamp = 'TURBO PASCAL HELP FILE.'#0
  18.               + #$1A
  19.               + '$*$* &&&&$*$'#0
  20.               + #$34#02;
  21.   FileStamp : array [0 .. Length (TPFileStamp) - 1] of Char = TPFileStamp;
  22.  
  23.   Of_CaseSense = $0004;
  24.  
  25.   CT_Nibble = 2;
  26.  
  27.   NC_RawChar = $F;
  28.   NC_RepChar = $E;
  29.  
  30. type
  31.   TRecType =
  32.     (RT_FileHeader,
  33.      RT_Context,
  34.      RT_Text,
  35.      RT_Keyword,
  36.      RT_Index,
  37.      RT_Compression,
  38.      RT_ScreenTags);
  39.  
  40.   TRecHdr = record
  41.     RecType: TRecType;
  42.     RecLength: Word;
  43.   end;
  44.  
  45.   TPFileHdrRec = record
  46.     Options: Word;
  47.     MainIndexScreen: Word;
  48.     MaxScreenSize: Word;
  49.     Height: Byte;
  50.     Width: Byte;
  51.     LeftMargin: Byte;
  52.   end;
  53.  
  54.   TPCompRec = record
  55.     CompType: Byte;
  56.     CharTable: array [0..13] of Char;
  57.   end;
  58.  
  59.   TFileStart = record
  60.     FileHdr_ : TRecHdr;
  61.     FileHdr  : TPFileHdrRec;
  62.     CompRec_ : TRecHdr;
  63.     CompRec  : TPCompRec;
  64.   end;
  65.  
  66.   PCtxTbl = ^TCtxTbl;
  67.   TCtxTbl = record
  68.     N: Word;
  69.     T: array [0..16382] of Longint;
  70.   end;
  71.  
  72.   TCharCounter = array [Char] of Longint;
  73.  
  74.   PIdxTbl = ^TIdxTbl;
  75.   TIdxTbl = object (TSortedCollection)
  76.     function  KeyOf (Item: Pointer): Pointer; virtual;
  77.     function  Compare (Key1, Key2: Pointer): Integer; virtual;
  78.     procedure SetCtxs;
  79.     function  RealCount: Word;
  80.     procedure Write (var S: TStream);
  81.     procedure AltWrite (var S: TStream; const GlobalAltName: string);
  82.     procedure ReBuild (Level: Integer);
  83.   end;
  84.  
  85.   PTopic = ^TTopic;
  86.   TTopic = object (TStringCollection)
  87.     Size: Longint;
  88.     Keywords: TStringCollection;
  89.     InSwap: Boolean;
  90.     SwapPos: Longint;
  91.  
  92.     constructor Init(ALimit, ADelta: Integer);
  93.  
  94.     procedure   Store2Swap (var S: TStream);
  95.     procedure   RestoreFromSwap (var S: TStream);
  96.  
  97.     procedure   AddString (S: string);
  98.     procedure   UpdateCharCounter (var C: TCharCounter);
  99.     procedure   Write (var S: TStream; Compression: TPCompRec);
  100.  
  101.     procedure   AddKeyword (S: string; StepBack: Integer);
  102.     procedure   WriteKeywords (var S: TStream; var IdxTbl: TIdxTbl);
  103.   end;
  104.  
  105.   PIndexEntry = ^TIndexEntry;
  106.   TIndexEntry = object (TObject)
  107.     PS, PS1: PString;
  108.     Ctx: Word;
  109.     Topic: PTopic;
  110.     Indexed: Boolean;
  111.  
  112.     constructor Init (const S, S1: string; ACtx: Word; var ATopic: PTopic; IsIndexed: Boolean);
  113.     procedure   Write (var S: TStream; const PrevStr: string);
  114.     procedure   AltWrite (var S: TStream);
  115.     destructor  Done; virtual;
  116.   end;
  117.  
  118.   PHelpFile = ^THelpFile;
  119.   THelpFile = object (TBufStream)
  120.     FileStart: TFileStart;
  121.     CtxTbl: PCtxTbl;
  122.     IdxTbl: TIdxTbl;
  123.  
  124.     constructor Init(FileName: FNameStr; Mode, Size: Word);
  125.     destructor  Done; virtual;
  126.   end;
  127.  
  128. var
  129.   SwapFile: PBufStream;
  130.  
  131. implementation
  132.  
  133. uses
  134.   Upcaser;
  135.  
  136. procedure CharCounter2CompRec (var C: TCharCounter; var R: TPCompRec);
  137. var I: Integer;
  138.     J, MC: Char;
  139.     M: Longint;
  140. begin
  141.   for I := Low (R. CharTable) + 1 to High (R. CharTable) do begin
  142.     M := 0;
  143.     MC := #0;
  144.  
  145.     for J := Low (C) to High (C) do
  146.       if C [J] > M then begin
  147.         MC := J;
  148.         M := C [J];
  149.       end;
  150.  
  151.     R. CharTable [I] := MC;
  152.     C [MC] := 0;
  153.   end;
  154. end;
  155.  
  156. { TTopic = object (TStringCollection) }
  157.  
  158. constructor TTopic. Init(ALimit, ADelta: Integer);
  159. begin
  160.   inherited Init (ALimit, ADelta);
  161.   Size := 0;
  162.   Keywords. Init (ALimit, ADelta);
  163.  
  164.   InSwap := False;
  165.   SwapPos := -1;
  166. end;
  167.  
  168. procedure   TTopic. Store2Swap (var S: TStream);
  169. var I: Integer;
  170. begin
  171.   if not InSwap then begin
  172.     if SwapPos = -1 then begin
  173.       SwapPos := S. GetSize;
  174.       S. Seek (SwapPos);
  175.       S. Write (Count, 2);
  176.       if Count > 1 then
  177.         for I := 1 to Count - 1 do begin
  178.           S. WriteStr (Items^[I]);
  179.           DisposeStr (Items^[I]);
  180.           Items^[I] := nil;
  181.         end;
  182.     end else
  183.       if Count > 1 then
  184.         for I := 1 to Count - 1 do begin
  185.           DisposeStr (Items^[I]);
  186.           Items^[I] := nil;
  187.         end;
  188.  
  189.     InSwap := True;
  190.   end;
  191. end;
  192.  
  193. procedure   TTopic. RestoreFromSwap (var S: TStream);
  194. var I, C: Integer;
  195. begin
  196.   if InSwap then
  197.     if SwapPos = -1 then begin
  198.       WriteLn ('Swapping error 2');
  199.       Halt (1);
  200.     end else begin
  201.       S. Seek (SwapPos);
  202.       S. Read (C, 2);
  203.       if C > 1 then
  204.         for I := 1 to C - 1 do
  205.           Items^[I] := S. ReadStr;
  206.       InSwap := False;
  207.     end;
  208. end;
  209.  
  210. procedure   TTopic. AddString (S: string);
  211. var I, J: Integer;
  212. begin
  213.   AtInsert (Count, NewStr (S));
  214.  
  215.   if Length (S) < 77 then begin
  216.     Inc (Size, Length (S) + 1);
  217.   end else begin
  218.     I := 77;
  219.  
  220.     while (I > Length (S) - 75) and (S [I] <> ' ') do
  221.       Dec (I);
  222.  
  223.     Inc (Size, I);
  224.  
  225.     J := I - 1 - (Length (S) - I + 1);
  226.     if J < 0 then
  227.       J := 0;
  228.  
  229.     Inc (Size, J + Length (S) - I + 1 + 1);
  230.   end;
  231.  
  232.   if Size > 65535 then
  233.     WriteLn ('error 1');
  234. end;
  235.  
  236. procedure TTopic. UpdateCharCounter (var C: TCharCounter);
  237.   procedure DoOneString (PS: PString); far;
  238.   var I: Integer;
  239.   begin
  240.     if PS <> nil then
  241.       for I := 1 to Length (PS^) do
  242.         Inc (C [PS^ [I]]);
  243.   end;
  244. begin
  245.   RestoreFromSwap (SwapFile^);
  246.   ForEach (@DoOneString);
  247.   Store2Swap (SwapFile^);
  248. end;
  249.  
  250. procedure TTopic. Write (var S: TStream; Compression: TPCompRec);
  251. var
  252.   Buf: Byte;
  253.   Nibble: Integer;
  254.  
  255.   procedure  WriteNibble (X: Byte);
  256.   begin
  257.     if Nibble = 0 then begin
  258.       Buf := X;
  259.       Nibble := 1;
  260.     end else begin
  261.       Buf := Buf + X shl 4;
  262.       S. Write (Buf, 1);
  263.       Nibble := 0;
  264.     end;
  265.   end;
  266.  
  267.   procedure  WriteChar (C: Char);
  268.   var I: Integer;
  269.   begin
  270.     I := Pos (C, Compression. CharTable);
  271.     if I > 0 then
  272.       WriteNibble (I - 1)
  273.     else begin
  274.       WriteNibble (NC_RawChar);
  275.       WriteNibble (Ord (C) and $F);
  276.       WriteNibble (Ord (C) shr 4);
  277.     end;
  278.   end;
  279.  
  280.   procedure WriteOneString (PS: PString); far;
  281.     procedure DoWrite (const S: string);
  282.     var I, J: Integer;
  283.     begin
  284.       for I := 1 to Length (S) do begin
  285.         J := I + 1;
  286.         while (J <= Length (S)) and (S [J] = S [I]) do
  287.          Inc (J);
  288.         if ((Pos (S [I], Compression. CharTable) = 0) and (J - I > 1))
  289.         or (J - I > 2) then begin
  290.           WriteNibble (NC_RepChar);
  291.           if J - I > 17 then
  292.             J := I + 17;
  293.           WriteNibble (J - I - 2);
  294.           WriteChar (S [I]);
  295.           I := J - 1;
  296.         end else
  297.           WriteChar (S [I]);
  298.       end;
  299.  
  300.       WriteNibble (0);
  301.     end;
  302.   var I, J, KeyCnt: Integer;
  303.       Spcs: string;
  304.   begin
  305.     if PS <> nil then
  306.       if Length (PS^) < 77 then
  307.         DoWrite (PS^)
  308.       else begin
  309.         KeyCnt := 0;
  310.         for I := 1 to 76 do
  311.           if PS^ [I] = #2 then
  312.             Inc (KeyCnt);
  313.         I := 77;
  314.  
  315.         while Odd (KeyCnt)
  316.         or   ((I > Length (PS^) - 75)
  317.           and (not (PS^ [I] in [' ']))
  318.           and (not (PS^ [I - 1] in [','])))
  319.         do begin
  320.           Dec (I);
  321.           if PS^ [I] = #2 then
  322.             Dec (KeyCnt);
  323.         end;
  324.  
  325.         DoWrite (Copy (PS^, 1, I - 1));
  326.  
  327.         J := I - 1 - (Length (PS^) - I + 1);
  328.         if J > 0 then begin
  329.           Spcs [0] := Chr (J);
  330.           FillChar (Spcs [1], Ord (Spcs [0]), ' ');
  331.         end else
  332.           Spcs := '';
  333.  
  334.         DoWrite (Spcs + Copy (PS^, I, Length (PS^) - I + 1));
  335.       end
  336.     else
  337.       DoWrite ('');
  338.   end;
  339.  
  340. var
  341.   R: TRecHdr;
  342.   TextRecStart,
  343.   TextRecEnd: Longint;
  344.  
  345. begin
  346.   RestoreFromSwap (SwapFile^);
  347.  
  348.   TextRecStart := S. GetPos;
  349.   R. RecType := RT_Text;
  350.   R. RecLength := 0;
  351.   S. Write (R, SizeOf (R));
  352.  
  353.   Nibble := 0;
  354.   ForEach (@WriteOneString);
  355.  
  356.   WriteChar (#1);
  357.  
  358.   if Nibble = 1 then
  359.     WriteNibble (0);
  360.  
  361.   TextRecEnd := S. GetPos;
  362.   R. RecLength := TextRecEnd - TextRecStart - SizeOf (R);
  363.   S. Seek (TextRecStart);
  364.   S. Write (R, SizeOf (R));
  365.   S. Seek (TextRecEnd);
  366.  
  367.   Store2Swap (SwapFile^);
  368. end;
  369.  
  370. procedure   TTopic. AddKeyword (S: string; StepBack: Integer);
  371. begin
  372.   Keywords. AtInsert (Keywords. Count - StepBack, NewStr (S));
  373. end;
  374.  
  375. procedure   TTopic. WriteKeywords (var S: TStream; var IdxTbl: TIdxTbl);
  376. var
  377.   R: TRecHdr;
  378.   TmpW: Word;
  379.   I, J, K, MinL, SaveMinLIdx, MatchLen, DecCnt: Integer;
  380.   TmpS, MatchS, Helper: string;
  381.   MatchFound: Boolean;
  382. begin
  383.   R. RecType := RT_Keyword;
  384.   R. RecLength := 6 + Keywords. Count * 2;
  385.   S. Write (R, SizeOf (R));
  386.  
  387.   TmpW := 0;
  388.   S. Write (TmpW, SizeOf (TmpW));
  389.   TmpW := 0;
  390.   S. Write (TmpW, SizeOf (TmpW));
  391.  
  392.   TmpW := Keywords. Count;
  393.   S. Write (TmpW, SizeOf (TmpW));
  394.  
  395.   if Keywords. Count > 0 then
  396.     for I := 0 to Keywords. Count - 1 do begin
  397.       TmpS := StUpcase2 (PString (Keywords. At (I))^);
  398.  
  399.       J := Pos ('"', TmpS);
  400.       if J > 0 then begin
  401.         if TmpS [Length (TmpS)] <> '"' then begin
  402.           Helper := '';
  403.           WriteLn ('error in keyword format - ', TmpS)
  404.         end else begin
  405.           Helper := Copy (TmpS, J + 1, Length (TmpS) - J - 1);
  406.           TmpS [0] := Chr (J - 1);
  407.         end;
  408.       end else
  409.         Helper := '';
  410.  
  411.       DecCnt := 0;
  412.  
  413.       MatchFound := False;
  414.       MinL := High (MinL);
  415.  
  416.       repeat
  417.         IdxTbl. Search (@TmpS, J);
  418.         for K := J to IdxTbl. Count - 1 do begin
  419.           MatchS := StUpcase2 (PIndexEntry (IdxTbl. At (K))^.PS^);
  420.           if Copy (MatchS, 1, Length (TmpS))
  421.           <> TmpS then
  422.             Break
  423.           else begin
  424.             if  ((Helper = '')
  425.               or (Pos (Helper, StUpcase2 (PString (PIndexEntry (
  426.                        IdxTbl. At (K))^. Topic^. At (0))^)) > 0))
  427.             and (Length (MatchS) - Length (TmpS) < MinL)
  428.             then begin
  429.               MinL := Length (MatchS) - Length (TmpS);
  430.               MatchLen := Length (TmpS);
  431.               SaveMinLIdx := K;
  432.             end;
  433.           end;
  434.         end;
  435.  
  436.         if (DecCnt < 2) and (MinL < High (MinL)) then begin
  437.           MatchFound := True;
  438.           J := SaveMinLIdx;
  439.         end;
  440.  
  441.         Dec (TmpS [0]);
  442.         Inc (DecCnt);
  443.       until MatchFound or (Length (TmpS) < 2);
  444.  
  445.       if (Helper <> '') and (MinL < High (MinL)) then
  446.         MinL := 0;
  447.  
  448.       if not MatchFound then begin
  449.         MatchFound := MinL < High (MinL);
  450.         J := SaveMinLIdx;
  451.       end;
  452.  
  453.       if  ( ((Helper = '') or (MinL = High (MinL)))
  454.         and (((MatchLen < 4) and (MinL > 0)) or (MinL > 1))
  455.           )
  456.       and (TmpS [1] in HexChars) and (TmpS [2] in HexChars) then begin
  457.         TmpS := 'INT ' + TmpS [1] + TmpS [2];
  458.         if not IdxTbl. Search (@TmpS, J) then begin
  459.           WriteLn ('error searching for - ', TmpS);
  460.         end else begin
  461.           MinL := 0;
  462.           MatchFound := True;
  463.         end;
  464.       end;
  465.  
  466.       if  ( ((Helper = '') or (MinL = High (MinL)))
  467.         and (((MatchLen < 5) and (MinL > 0)) or (MinL > 1))
  468.           )
  469.       and (TmpS [1] = 'P')
  470.       and (TmpS [2] in HexChars + ['x', 'X']) and (TmpS [3] in HexChars + ['x', 'X'])
  471.       and (TmpS [4] in HexChars + ['x', 'X']) and (TmpS [5] in HexChars + ['x', 'X']) then begin
  472.         TmpS := 'PORTS';
  473.         if not IdxTbl. Search (@TmpS, J) then begin
  474.           WriteLn ('error searching for - ', TmpS);
  475.         end else begin
  476.           MinL := 0;
  477.           MatchFound := True;
  478.         end;
  479.       end;
  480.  
  481.       TmpW := PIndexEntry (IdxTbl. At (J))^.Ctx;
  482.  
  483.       if not MatchFound then begin
  484.         WriteLn (PString (At (0))^);
  485.         WriteLn ('error searching for - ', PString (Keywords. At (I))^);
  486.         WriteLn ('found match         - ', PIndexEntry (IdxTbl. At (J))^.PS^);
  487.         TmpW := 1;
  488.       end else
  489.         if MinL > 1 then begin
  490.           WriteLn (PString (At (0))^);
  491.           WriteLn ('approximate match to - ', PString (Keywords. At (I))^);
  492.           WriteLn ('is                   - ', PIndexEntry (IdxTbl. At (J))^.PS^);
  493.           TmpW := 1;
  494.         end;
  495.  
  496.       S. Write (TmpW, SizeOf (TmpW));
  497.     end;
  498. end;
  499.  
  500. { TIndexEntry = object (TObject) }
  501.  
  502. constructor TIndexEntry. Init (const S, S1: string; ACtx: Word; var ATopic: PTopic; IsIndexed: Boolean);
  503. begin
  504.   inherited Init;
  505.   PS := NewStr (S);
  506.   PS1 := NewStr (S1);
  507.   Ctx := ACtx;
  508.  
  509.   Topic := ATopic;
  510.   ATopic := nil;
  511.   Topic^.Store2Swap (SwapFile^);
  512.  
  513.   Indexed := IsIndexed;
  514. end;
  515.  
  516. procedure   TIndexEntry. Write (var S: TStream; const PrevStr: string);
  517. var
  518.   RptChars: Integer;
  519.   LengthCode: Byte;
  520. begin
  521.   if Length (PS^) > 31 then
  522.     WriteLn ('error 2');
  523.  
  524.   RptChars := 0;
  525.   while (RptChars < Length (PrevStr))
  526.   and   (PS^ [RptChars + 1] = PrevStr [RptChars + 1]) do
  527.     Inc (RptChars);
  528.  
  529.   if Length (PS^) = RptChars then
  530.     WriteLn ('error - duplicate index entry!');
  531.  
  532.   if RptChars > 7 then
  533.     RptChars := 7;
  534.  
  535.   LengthCode := (Length (PS^) - RptChars)
  536.               + (RptChars) shl 5;
  537.  
  538.   S. Write (LengthCode, SizeOf (LengthCode));
  539.   S. Write (PS^ [RptChars + 1],  Length (PS^) - RptChars);
  540.   S. Write (Ctx, SizeOf (Ctx));
  541. end;
  542.  
  543. procedure   TIndexEntry. AltWrite (var S: TStream);
  544. var B: Byte;
  545. begin
  546.   if Length (PS1^) > 36 then
  547.     WriteLn ('error 2A');
  548.  
  549.   S. Write (Ctx, SizeOf (Ctx));
  550.   S. Write (PS1^,  Length (PS1^) + 1);
  551.   B := 0;
  552.   S. Write (B, SizeOf (B));
  553. end;
  554.  
  555. destructor  TIndexEntry. Done;
  556. begin
  557.   DisposeStr (PS1);
  558.   DisposeStr (PS);
  559.   inherited Done;
  560. end;
  561.  
  562. { TIdxTbl = object (TSortedCollection) }
  563.  
  564. function  TIdxTbl. KeyOf (Item: Pointer): Pointer;
  565. begin
  566.   KeyOf := PIndexEntry (Item)^. PS;
  567. end;
  568.  
  569. function  TIdxTbl. Compare (Key1, Key2: Pointer): Integer;
  570. begin
  571.   if (Key1 = nil) or (StUpcase2 (PString (Key1)^) < StUpcase2 (PString (Key2)^)) then
  572.     Compare := -1
  573.   else
  574.     if (Key2 <> nil) and (StUpcase2 (PString (Key1)^) = StUpcase2 (PString (Key2)^)) then
  575.       Compare := 0
  576.     else
  577.       Compare := 1;
  578. end;
  579.  
  580. procedure TIdxTbl. SetCtxs;
  581. var I: Integer;
  582. begin
  583.   for I := 0 to Count - 1 do
  584.     PIndexEntry (At (I))^. Ctx := I + 1;
  585. end;
  586.  
  587. function  TIdxTbl. RealCount: Word;
  588. var Cnt: Word;
  589.   procedure AddOne (var X: TIndexEntry); far;
  590.   begin
  591.     if  (X. PS <> nil)
  592.     and (X. PS^ <> '')
  593.     and  X. Indexed then
  594.       Inc (Cnt);
  595.   end;
  596. begin
  597.   Cnt := 0;
  598.   ForEach (@AddOne);
  599.   RealCount := Cnt;
  600. end;
  601.  
  602. procedure TIdxTbl. Write (var S: TStream);
  603. var PrevStr: string;
  604.   procedure WriteOne (var X: TIndexEntry); far;
  605.   begin
  606.     if  (X. PS <> nil)
  607.     and (X. PS^ <> '')
  608.     and  X. Indexed then begin
  609.       X. Write (S, PrevStr);
  610.       PrevStr := X. PS^;
  611.     end;
  612.   end;
  613. begin
  614.   PrevStr := '';
  615.   ForEach (@WriteOne);
  616. end;
  617.  
  618. procedure TIdxTbl. AltWrite (var S: TStream; const GlobalAltName: string);
  619.   procedure WriteOne (var X: TIndexEntry); far;
  620.   begin
  621.     if  (X. PS1 <> nil)
  622.     and (X. PS1^ <> '')
  623.     and  X. Indexed then
  624.       X. AltWrite (S);
  625.   end;
  626. var
  627.   TmpW: Word;
  628.   TmpS: string;
  629. begin
  630.   TmpW := $FFFF;
  631.   S. Write (TmpW, SizeOf (TmpW));
  632.  
  633.   TmpS := GlobalAltName;
  634.   TmpS [Length (GlobalAltName) + 1] := #0;
  635.   S. Write (TmpS, Length (GlobalAltName) + 2);
  636.  
  637.   ForEach (@WriteOne);
  638. end;
  639.  
  640. procedure TIdxTbl. ReBuild (Level: Integer);
  641. var PrevStr: string;
  642.   procedure ReBuildOne (var X: TIndexEntry); far;
  643.   var CurStr: string;
  644.       I: Integer;
  645.   begin
  646.     if  (X. PS <> nil)
  647.     and (X. PS^ <> '')
  648.     and  X.Indexed then begin
  649.       if Length (X. PS^) > Level then begin
  650.         CurStr := Copy (X. PS^, 1, Level);
  651.  
  652.         for I := Length (CurStr) downto 2 do
  653.           if CurStr [I] = ' ' then begin
  654.             CurStr [0] := Chr (I - 1);
  655.             Break;
  656.           end;
  657.  
  658.         DisposeStr (X. PS);
  659.         X. PS := NewStr (CurStr);
  660.       end;
  661.  
  662.       PrevStr := X. PS^;
  663.     end;
  664.   end;
  665. begin
  666.   PrevStr := '';
  667.   ForEach (@ReBuildOne);
  668. end;
  669.  
  670. { THelpFile = object (TBufStream) }
  671.  
  672. constructor THelpFile.Init(FileName: FNameStr; Mode, Size: Word);
  673. begin
  674.   inherited Init (FileName, Mode, Size);
  675.   if Mode = stCreate then begin
  676.     Write (FileStamp, SizeOf (FileStamp));
  677.  
  678.     with FileStart do begin
  679.       with FileHdr_ do begin
  680.         RecType := RT_FileHeader;
  681.         RecLength := SizeOf (FileHdr);
  682.       end;
  683.       with FileHdr do begin
  684.         Options := 0;
  685.         MainIndexScreen := 02;
  686.         MaxScreenSize := High (MaxScreenSize) and (-256);
  687.         Height := 24;
  688.         Width := 80;
  689.         LeftMargin := 0;
  690.       end;
  691.  
  692.       with CompRec_ do begin
  693.         RecType := RT_Compression;
  694.         RecLength := SizeOf (CompRec);
  695.       end;
  696.       with CompRec do begin
  697.         CompType := CT_Nibble;
  698.         FillChar (CharTable, SizeOf (CharTable), 0);
  699.       end;
  700.     end;
  701.   end;
  702.  
  703.   New (CtxTbl);
  704.   if Mode = stCreate then begin
  705.     CtxTbl^. N := 0;
  706.   end;
  707.  
  708.   IdxTbl. Init (MaxCollectionSize, 0);
  709.   IdxTbl. Duplicates := True;
  710. end;
  711.  
  712. destructor  THelpFile.Done;
  713. var I: Integer;
  714.     R: TRecHdr;
  715.     TmpW: Word;
  716.     StartPos,
  717.     EndPos,
  718.     CtxStart: Longint;
  719.     CC: TCharCounter;
  720. begin
  721.   System. Write ('building compression record...                        '#13);
  722.   FillChar (CC, SizeOf (CC), 0);
  723.   for I := 0 to IdxTbl.Count - 1 do
  724.     PIndexEntry (IdxTbl. At (I))^.Topic^.UpdateCharCounter (CC);
  725.   CharCounter2CompRec (CC, FileStart. CompRec);
  726.   WriteLn ('building compression record... done');
  727.  
  728.   Write (FileStart, SizeOf (FileStart));
  729.  
  730.   CtxTbl^. N := IdxTbl. Count + 1;
  731.   CtxTbl^. T [0] := $FFFFFFFF;
  732.  
  733.   R. RecType := RT_Context;
  734.   R. RecLength := 2 + CtxTbl^. N * 3;
  735.   Write (R, SizeOf (R));
  736.   Write (CtxTbl^. N, SizeOf (CtxTbl^. N));
  737.   CtxStart := GetPos;
  738.   if CtxTbl^. N > 0 then
  739.     for I := 0 to CtxTbl^. N - 1 do
  740.       Write (CtxTbl^.T [I], 3);
  741.  
  742.   IdxTbl. SetCtxs;
  743.  
  744.   I := 31;
  745.   repeat
  746.     StartPos := GetPos;
  747.     R. RecType := RT_Index;
  748.     R. RecLength := 0;
  749.     Write (R, SizeOf (R));
  750.     TmpW := IdxTbl. RealCount;
  751.     Write (TmpW, 2);
  752.     IdxTbl. Write (Self);
  753.     EndPos := GetPos;
  754.     WriteLn ('index size - ', EndPos - StartPos - SizeOf (R));
  755.     Seek (StartPos);
  756.     if EndPos - StartPos - SizeOf (R) >= 65536 then begin
  757.       Dec (I);
  758.       WriteLn ('rebuilding index - level ', I);
  759.       IdxTbl. ReBuild (I);
  760.     end;
  761.   until EndPos - StartPos - SizeOf (R) < 65536;
  762.   R. RecLength := EndPos - StartPos - SizeOf (R);
  763.   Write (R, SizeOf (R));
  764.   Seek (EndPos);
  765.  
  766.   StartPos := GetPos;
  767.   R. RecType := RT_ScreenTags;
  768.   R. RecLength := 0;
  769.   Write (R, SizeOf (R));
  770.   IdxTbl. AltWrite (Self, 'Interrupt List');
  771.   EndPos := GetPos;
  772.   WriteLn ('alternative index size - ', EndPos - StartPos - SizeOf (R));
  773.   Seek (StartPos);
  774.   if EndPos - StartPos - SizeOf (R) >= 65536 then begin
  775.     WriteLn ('alternative index is too large.');
  776.     Halt (1);
  777.   end;
  778.   R. RecLength := EndPos - StartPos - SizeOf (R);
  779.   Write (R, SizeOf (R));
  780.   Seek (EndPos);
  781.  
  782.   for I := 0 to IdxTbl.Count - 1 do begin
  783.     CtxTbl^. T [PIndexEntry (IdxTbl. At (I))^.Ctx] := GetPos;
  784.     PIndexEntry (IdxTbl. At (I))^.Topic^.Write (Self, FileStart. CompRec);
  785.  
  786.     PIndexEntry (IdxTbl. At (I))^.Topic^.WriteKeywords (Self, IdxTbl);
  787.  
  788.     System. Write (I, #13);
  789.   end;
  790.  
  791.   Seek (CtxStart);
  792.   if CtxTbl^. N > 0 then
  793.     for I := 0 to CtxTbl^. N - 1 do
  794.       Write (CtxTbl^.T [I], 3);
  795.  
  796.   IdxTbl. Done;
  797.   if CtxTbl <> nil then
  798.     Dispose (CtxTbl);
  799.   inherited Done;
  800. end;
  801.  
  802. end.
  803.